﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Entity;
using System.Data;
using System.Text;
using System.Threading.Tasks;
using DataRepositoryLayer.Interfaces;
using DataAccessLayer;

namespace DataRepositoryLayer.Classes
{
    public class GenericDataRepository<T> : IGenericDataRepository<T> where T : class
    {

        protected readonly ElectricCarEntities context;

        public GenericDataRepository(IUnitOfWork unitOfWork)
        {

            context = (ElectricCarEntities) ((UnitOfWork)unitOfWork).Context;
        }

        public virtual IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties) 
        {
            
            List<T> list;

            IQueryable<T> queryObject = context.Set<T>();

            foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
            {
                queryObject = queryObject.Include<T, object>(navigationProperty);
            }

            list = queryObject.AsNoTracking().ToList<T>();

            return list;
        }

        public virtual IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties)
        {
            List<T> list;
            IQueryable<T> queryObject = context.Set<T>();

            //Apply eager loading
            foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
            {
                queryObject = queryObject.Include<T, object>(navigationProperty);
            }

            list = queryObject.AsNoTracking().Where(where).ToList<T>();
            return list;
        }

        public virtual T GetSingle(Func<T, bool> where, params System.Linq.Expressions.Expression<Func<T, object>>[] navigationProperties)
        {
            T item = null;
            IQueryable<T> queryObject = context.Set<T>();
           
           

            //Apply eager loading
            foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
                queryObject = queryObject.Include<T, object>(navigationProperty);

            item = queryObject.AsNoTracking() //Don't track any changes for the selected item
                .SingleOrDefault(where); //Apply where clause       //will return null is nothing is found
            return item;
        }

        public virtual void AddMultiple(params T[] objectsToInsert)
        {
            foreach (T item in objectsToInsert)
            {
                context.Entry(item).State = EntityState.Added;
            }
        }

        public virtual void UpdateMultiple(params T[] objectsToUpdate)
        {
            foreach (T item in objectsToUpdate)
            {
                context.Entry(item).State = EntityState.Modified;
            }
        }

        public virtual void RemoveMultiple(params T[] objectsToRemove)
        {
            foreach (T item in objectsToRemove)
            {
                context.Entry(item).State = EntityState.Deleted;
            }
        }


        public void Add(T item)
        {
            context.Entry(item).State = EntityState.Added;
        }

        public void Update(T item)
        {
            context.Entry(item).State = EntityState.Modified;
        }

        public void Remove(T item)
        {
            context.Entry(item).State = EntityState.Deleted;
        }
    }
}
